#include "Game.h"

#include "../Input/Input.h"
#include "../Renderer/D3D9Renderer.h"
#include "../Utility/Math/MathHelper.h"
#include "../EventSystem/EventSystem.h"
#include "../Renderer/Utility/TextureManager.h"

#include <fstream>
using std::ifstream;
using std::ios_base;
#include <iostream>
using std::cin;

#ifdef _DEBUG
#include "../Utility/Misc/DebugOutput.h"
#include<sstream>
using std::stringstream;
#endif

bool			Game::isRunning;
Timer			Game::timer;
HTable<string>	Game::dictionary(500, HashFunc);
BaseState*		Game::currentState;
bool			Game::gameOver;

bool Game::Initialize(HWND _hWnd, bool _bFullscreen, bool _bVsync, int _nScreenWidth, int _nScreenHeight)
{
	timer.Init();
	Input::Init();

	if(D3D9Renderer::Initialize(_hWnd, false, false, 300, 400))
	{
		isRunning = true;
	}

	EventSystem::RegisterClient(EVENT_INPUT, HandleKeyInput);

	LoadDictionary();

	ChangeGameState(MainGame::GetInstance());

	gameOver = false;

	return true;
}

void Game::Run()
{
	Update();
	Render();
}

void Game::Render()
{
	D3D9Renderer::Clear(0,0, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);

	D3D9Renderer::BeginScene();
	//D3D9Renderer::BeginSprite();
	
	{
		currentState->Render();
	}

	//D3D9Renderer::EndSprite();
	D3D9Renderer::EndScene();

	D3D9Renderer::Present(0, 0, 0, 0);
}

void Game::Update()
{
	//DisplayMousePos();
	currentState->Update(timer.GetDeltaTimeFloat() / 1000.0f);
	CalculateFrameStats();
	Input::Update();


	timer.TimeStep();

	EventSystem::ProcessEvents();
}

void Game::Exit()
{
	TextureManager::Shutdown();
	D3D9Renderer::Shutdown();
	EventSystem::ShutdownEventSystem();

	EventSystem::UnregisterClient(EVENT_INPUT, HandleKeyInput);
}

void Game::HandleKeyInput(Event* _event)
{
	InputEvent* inputEvent = (InputEvent*)_event->GetParam();

	short inputflag = inputEvent->GetInputFlags();
	if(inputEvent->GetInputFlags() & ESCAPE_EVENT)
	{
		Game::isRunning = false;
	}
}

void Game::CalculateFrameStats()
{
	static int frameCount = 0;
	static float elapsedTime = 0.0f;

	elapsedTime += (timer.GetDeltaTimeFloat() / 1000.0f);

	frameCount ++;

	if(elapsedTime >= 1.0f)
	{
		float framesPerSec = frameCount / elapsedTime;

		char MyInfo[16];
		sprintf_s(MyInfo, "%f", framesPerSec);

		string FPS;
		FPS += MyInfo;
		SetWindowText(D3D9Renderer::hwnd, FPS.c_str());

		elapsedTime = 0.0f;
		frameCount = 0;
	}
}

void Game::DisplayMousePos()
{
	POINT cursorPos;;
	GetCursorPos(&cursorPos);
	ScreenToClient(D3D9Renderer::hwnd, &cursorPos);
	int xPos = (int)cursorPos.x;//(int)Input::GetCursorPosition().x;
	int yPos = (int)cursorPos.y;//(int)Input::GetCursorPosition().y;

	char x[16];
	sprintf_s(x, "%i", xPos);
	char y[16];
	sprintf_s(y, "%i", yPos);
	
	string mousePos;
	mousePos += "X: ";
	mousePos += x;
	mousePos += ", Y: ";
	mousePos += y;

	SetWindowText(D3D9Renderer::hwnd, mousePos.c_str());
}

void Game::LoadDictionary()
{
	bool apostrophe = false;
	ifstream in("Res/engldict.txt");
	if(in.is_open())
	{
		while(!in.eof())
		{
			bool quit = true;
			string words;
			getline(in, words);
			for(unsigned int x = 0; x < words.size(); x ++)
			{
				if(words[x] == '\'')
				{
					apostrophe = true;
				}
			}
			if(words.length() <= 16 && words.length() >= 3 && !apostrophe)
			{
				for(unsigned int x = 0; x < words.length(); x++)
				{
					if(words[x] == '\'')
						quit = false;
				}
				if(quit)
				{
					dictionary.insert(words);
				}
			}
			apostrophe = false;
		}
		in.close();
	}
}

unsigned int Game::HashFunc(const string& Hash)
{
	unsigned int total = 0;
	for(unsigned int x = 0; x < Hash.length(); x++)
	{
		total = total + 3 * Hash[x] + BUCKETS;
	}
	return total % BUCKETS;
}

void Game::ChangeGameState(BaseState* _newState)
{
	currentState = _newState;

	currentState->Initialize();
}